Main.overview.connect('hidden',
Lang.bind(this, this._onFocusAppChanged));
- this._trayManager.manage_stage(global.stage, Main.messageTray.actor);
+ this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
},
_imageForNotificationData: function(hints) {
#include "shell-embedded-window-private.h"
/* This type is a subclass of GtkWindow that ties the window to a
- * ShellGtkEmbed; the window is reparented into the stage
- * window for the actor and the resizing logic is bound to the clutter
- * logic.
+ * ShellGtkEmbed; the resizing logic is bound to the clutter logic.
*
* The typical usage we might expect is
*
G_DEFINE_TYPE (ShellEmbeddedWindow, shell_embedded_window, GTK_TYPE_WINDOW);
enum {
- PROP_0,
-
- PROP_STAGE
+ PROP_0
};
struct _ShellEmbeddedWindowPrivate {
ShellGtkEmbed *actor;
GdkRectangle position;
- Window stage_xwindow;
};
/*
GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->hide (widget);
}
-static void
-shell_embedded_window_realize (GtkWidget *widget)
-{
- ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
-
- GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->realize (widget);
-
-
- /* Using XReparentWindow() is simpler than using gdk_window_reparent(),
- * since it avoids maybe having to create a new foreign GDK window for
- * the stage. However, GDK will be left thinking that the parent of
- * window->window is the root window - it's not immediately clear
- * to me whether that is more or less likely to cause problems than
- * modifying the GDK hierarchy.
- */
- XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
- gdk_x11_window_get_xid (gtk_widget_get_window (widget)),
- window->priv->stage_xwindow,
- window->priv->position.x, window->priv->position.y);
-}
-
static gboolean
shell_embedded_window_configure_event (GtkWidget *widget,
GdkEventConfigure *event)
clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
}
-static void
-shell_embedded_window_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object);
-
- switch (prop_id)
- {
- case PROP_STAGE:
- window->priv->stage_xwindow =
- clutter_x11_get_stage_window (g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
static GObject *
shell_embedded_window_constructor (GType gtype,
guint n_properties,
g_type_class_add_private (klass, sizeof (ShellEmbeddedWindowPrivate));
- object_class->set_property = shell_embedded_window_set_property;
object_class->constructor = shell_embedded_window_constructor;
widget_class->show = shell_embedded_window_show;
widget_class->hide = shell_embedded_window_hide;
- widget_class->realize = shell_embedded_window_realize;
widget_class->configure_event = shell_embedded_window_configure_event;
container_class->check_resize = shell_embedded_window_check_resize;
-
- g_object_class_install_property (object_class,
- PROP_STAGE,
- g_param_spec_object ("stage",
- "Stage",
- "ClutterStage to embed on",
- CLUTTER_TYPE_STAGE,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
static void
* Public API
*/
GtkWidget *
-shell_embedded_window_new (ClutterStage *stage)
+shell_embedded_window_new (void)
{
return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW,
- "stage", stage,
NULL);
}
};
GType shell_embedded_window_get_type (void) G_GNUC_CONST;
-GtkWidget *shell_embedded_window_new (ClutterStage *stage);
+GtkWidget *shell_embedded_window_new (void);
#endif /* __SHELL_EMBEDDED_WINDOW_H__ */
#include "config.h"
#include "shell-embedded-window-private.h"
+#include "shell-global.h"
#include <gdk/gdkx.h>
+#include <meta/display.h>
+#include <meta/window.h>
enum {
PROP_0,
struct _ShellGtkEmbedPrivate
{
ShellEmbeddedWindow *window;
+
+ ClutterActor *window_actor;
+ guint window_actor_destroyed_handler;
+
+ guint window_created_handler;
};
-G_DEFINE_TYPE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
+G_DEFINE_TYPE (ShellGtkEmbed, shell_gtk_embed, CLUTTER_TYPE_CLONE);
static void shell_gtk_embed_set_window (ShellGtkEmbed *embed,
ShellEmbeddedWindow *window);
}
static void
-shell_gtk_embed_on_window_realize (GtkWidget *widget,
+shell_gtk_embed_remove_window_actor (ShellGtkEmbed *embed)
+{
+ ShellGtkEmbedPrivate *priv = embed->priv;
+
+ if (priv->window_actor)
+ {
+ g_signal_handler_disconnect (priv->window_actor,
+ priv->window_actor_destroyed_handler);
+ priv->window_actor_destroyed_handler = 0;
+
+ g_object_unref (priv->window_actor);
+ priv->window_actor = NULL;
+ }
+
+ clutter_clone_set_source (CLUTTER_CLONE (embed), NULL);
+}
+
+static void
+shell_gtk_embed_window_created_cb (MetaDisplay *display,
+ MetaWindow *window,
ShellGtkEmbed *embed)
{
- /* Here automatic=FALSE means to use CompositeRedirectManual.
- * That is, the X server shouldn't draw the window onto the
- * screen.
- */
- clutter_x11_texture_pixmap_set_window (CLUTTER_X11_TEXTURE_PIXMAP (embed),
- gdk_x11_window_get_xid (gtk_widget_get_window (widget)),
- FALSE);
+ ShellGtkEmbedPrivate *priv = embed->priv;
+ Window xwindow = meta_window_get_xwindow (window);
+ GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (priv->window));
+
+ if (xwindow == gdk_x11_window_get_xid (gdk_window))
+ {
+ ClutterActor *window_actor =
+ CLUTTER_ACTOR (meta_window_get_compositor_private (window));
+ MetaDisplay *display = shell_global_get_display (shell_global_get ());
+ GCallback remove_cb = G_CALLBACK (shell_gtk_embed_remove_window_actor);
+ cairo_region_t *empty_region;
+
+ clutter_clone_set_source (CLUTTER_CLONE (embed), window_actor);
+
+ /* We want to explicitly clear the clone source when the window
+ actor is destroyed because otherwise we might end up keeping
+ it alive after it has been disposed. Otherwise this can cause
+ a crash if there is a paint after mutter notices that the top
+ level window has been destroyed, which causes it to dispose
+ the window, and before the tray manager notices that the
+ window is gone which would otherwise reset the window and
+ unref the clone */
+ priv->window_actor = g_object_ref (window_actor);
+ priv->window_actor_destroyed_handler =
+ g_signal_connect_swapped (window_actor,
+ "destroy",
+ remove_cb,
+ embed);
+
+ /* Hide the original actor otherwise it will appear in the scene
+ as a normal window */
+ clutter_actor_set_opacity (window_actor, 0);
+
+ /* Set an empty input shape on the window so that it can't get
+ any input. This probably isn't the ideal way to acheive this.
+ It would probably be better to force the window to go behind
+ Mutter's guard window, but this is quite difficult to do as
+ Mutter doesn't manage the stacking for override redirect
+ windows and the guard window is repeatedly lowered to the
+ bottom of the stack. */
+ empty_region = cairo_region_create ();
+ gdk_window_input_shape_combine_region (gdk_window,
+ empty_region,
+ 0, 0 /* offset x/y */);
+ cairo_region_destroy (empty_region);
+
+ /* Now that we've found the window we don't need to listen for
+ new windows anymore */
+ g_signal_handler_disconnect (display,
+ priv->window_created_handler);
+ priv->window_created_handler = 0;
+ }
}
static void
shell_gtk_embed_set_window (ShellGtkEmbed *embed,
ShellEmbeddedWindow *window)
{
+ MetaDisplay *display = shell_global_get_display (shell_global_get ());
if (embed->priv->window)
{
+ if (embed->priv->window_created_handler)
+ {
+ g_signal_handler_disconnect (display,
+ embed->priv->window_created_handler);
+ embed->priv->window_created_handler = 0;
+ }
+
+ shell_gtk_embed_remove_window_actor (embed);
+
_shell_embedded_window_set_actor (embed->priv->window, NULL);
g_object_unref (embed->priv->window);
- clutter_x11_texture_pixmap_set_window (CLUTTER_X11_TEXTURE_PIXMAP (embed),
- None,
- FALSE);
-
g_signal_handlers_disconnect_by_func (embed->priv->window,
(gpointer)shell_gtk_embed_on_window_destroy,
embed);
- g_signal_handlers_disconnect_by_func (embed->priv->window,
- (gpointer)shell_gtk_embed_on_window_realize,
- embed);
}
embed->priv->window = window;
g_signal_connect (embed->priv->window, "destroy",
G_CALLBACK (shell_gtk_embed_on_window_destroy), embed);
- g_signal_connect (embed->priv->window, "realize",
- G_CALLBACK (shell_gtk_embed_on_window_realize), embed);
- if (gtk_widget_get_realized (GTK_WIDGET (window)))
- shell_gtk_embed_on_window_realize (GTK_WIDGET (embed->priv->window), embed);
+ /* Listen for new windows so we can detect when Mutter has
+ created a MutterWindow for this window */
+ embed->priv->window_created_handler =
+ g_signal_connect (display,
+ "window-created",
+ G_CALLBACK (shell_gtk_embed_window_created_cb),
+ embed);
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (embed));
{
embed->priv = G_TYPE_INSTANCE_GET_PRIVATE (embed, SHELL_TYPE_GTK_EMBED,
ShellGtkEmbedPrivate);
-
- /* automatic here means whether ClutterX11TexturePixmap should
- * process damage update and refresh the pixmap itself.
- */
- clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (embed), TRUE);
}
/*
#ifndef __SHELL_GTK_EMBED_H__
#define __SHELL_GTK_EMBED_H__
-#include <clutter/x11/clutter-x11.h>
+#include <clutter/clutter.h>
#include "shell-embedded-window.h"
struct _ShellGtkEmbed
{
- ClutterX11TexturePixmap parent;
+ ClutterClone parent;
ShellGtkEmbedPrivate *priv;
};
struct _ShellGtkEmbedClass
{
- ClutterX11TexturePixmapClass parent_class;
+ ClutterCloneClass parent_class;
};
GType shell_gtk_embed_get_type (void) G_GNUC_CONST;
#include "shell-window-tracker.h"
#include "tray/na-tray-child.h"
#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
#include "st.h"
enum {
struct _ShellTrayManagerPrivate {
NaTrayManager *na_manager;
- ClutterStage *stage;
ClutterColor bg_color;
GHashTable *icons;
ShellTrayManager *manager = SHELL_TRAY_MANAGER (object);
g_object_unref (manager->priv->na_manager);
- g_object_unref (manager->priv->stage);
g_hash_table_destroy (manager->priv->icons);
G_OBJECT_CLASS (shell_tray_manager_parent_class)->finalize (object);
}
void
-shell_tray_manager_manage_stage (ShellTrayManager *manager,
- ClutterStage *stage,
- StWidget *theme_widget)
+shell_tray_manager_manage_screen (ShellTrayManager *manager,
+ MetaScreen *screen,
+ StWidget *theme_widget)
{
- Window stage_xwindow;
- GdkWindow *stage_window;
GdkDisplay *display;
- GdkScreen *screen;
+ GdkScreen *gdk_screen;
+ int screen_number;
- g_return_if_fail (manager->priv->stage == NULL);
+ display = gdk_display_get_default ();
+ screen_number = meta_screen_get_screen_number (screen);
+ gdk_screen = gdk_display_get_screen (display, screen_number);
- manager->priv->stage = g_object_ref (stage);
-
- stage_xwindow = clutter_x11_get_stage_window (stage);
-
- /* This is a pretty ugly way to get the GdkScreen for the stage; it
- * will normally go through the foreign_new() case with a
- * round-trip to the X server, it might be nicer to pass the screen
- * in in some way. (The Clutter/Mutter combo is currently incapable
- * of multi-screen operation, so alternatively we could just assume
- * that clutter_x11_get_default_screen() gives us the right
- * screen.) We assume, in any case, that we are using the default
- * GDK display.
- */
- display = gdk_display_get_default();
- stage_window = gdk_x11_window_lookup_for_display (display, stage_xwindow);
- if (stage_window)
- g_object_ref (stage_window);
- else
- stage_window = gdk_x11_window_foreign_new_for_display (display, stage_xwindow);
-
- screen = gdk_window_get_screen (stage_window);
-
- g_object_unref (stage_window);
-
- na_tray_manager_manage_screen (manager->priv->na_manager, screen);
+ na_tray_manager_manage_screen (manager->priv->na_manager, gdk_screen);
g_signal_connect (theme_widget, "style-changed",
G_CALLBACK (shell_tray_manager_style_changed), manager);
*/
na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);
- win = shell_embedded_window_new (manager->priv->stage);
+ win = shell_embedded_window_new ();
gtk_container_add (GTK_CONTAINER (win), socket);
/* The visual of the socket matches that of its contents; make
GType shell_tray_manager_get_type (void);
ShellTrayManager *shell_tray_manager_new (void);
-void shell_tray_manager_manage_stage (ShellTrayManager *manager,
- ClutterStage *stage,
- StWidget *theme_widget);
+void shell_tray_manager_manage_screen (ShellTrayManager *manager,
+ MetaScreen *screen,
+ StWidget *theme_widget);
G_END_DECLS